package com.xiyu.service.framework.mail.service;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.xiyu.service.enums.mailbox.mail.MailboxMailResourceTypeEnum;
import com.xiyu.service.enums.market.task.MarketTaskStatusEnum;
import com.xiyu.service.model.customer.contact.CustomerContact;
import com.xiyu.service.model.market.setting.MarketSettingDomain;
import com.xiyu.service.model.market.setting.MarketSettingSender;
import com.xiyu.service.model.market.task.MarketTask;
import com.xiyu.service.model.market.task.MarketTaskReceiver;
import com.xiyu.service.model.market.task.MarketTaskReceiverDraft;
import com.xiyu.service.model.market.task.MarketTaskResource;
import com.xiyu.service.model.system.user.SystemUser;
import com.xiyu.service.repository.customer.contact.CustomerContactRepository;
import com.xiyu.service.repository.market.setting.MarketSettingSenderRepository;
import com.xiyu.service.repository.market.task.MarketTaskReceiverRepository;
import com.xiyu.service.repository.market.task.MarketTaskRepository;
import com.xiyu.service.repository.system.user.SystemUserRepository;
import com.xiyu.service.service.infra.file.FileService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

@Component
@Scope("prototype")
@Slf4j
public class BatchSendMailService {

    @Resource
    MarketSettingSenderRepository marketSettingSenderRepository;

    @Resource
    CustomerContactRepository customerContactRepository;

    @Resource
    SystemUserRepository systemUserRepository;

    @Resource
    MarketTaskReceiverRepository marketTaskReceiverRepository;

    @Resource
    MarketTaskRepository marketTaskRepository;

    @Resource
    FileService fileService;

    final String mailSendUrl = "https://api.sendcloud.net/apiv2/mail/send";

    final String webhookListUrl = "https://api.sendcloud.net/apiv2/webhook/list";

    final String webhookAddUrl = "https://api.sendcloud.net/apiv2/webhook/add";

    final String addressListAddUrl = "https://api.sendcloud.net/apiv2/addresslist/add";

    final String addressMemberAddUrl = "https://api.sendcloud.net/apiv2/addressmember/add";

    final ContentType textPlainType = ContentType.create("text/plain", StandardCharsets.UTF_8);

    final ContentType octetSteamType = ContentType.create("application/octet-stream", StandardCharsets.UTF_8);

    public String marketTaskExec(MarketTask task) throws Exception {

        MarketSettingSender sender = marketSettingSenderRepository.findDetailById(task.senderId()).orElse(null);
        // 增加异常判断
        if(sender == null){
            return "发送邮件出现错误，营销发件人不存在";
        }

        if(sender.domain() == null){
            return "发送邮件出现错误，营销域名不存在";
        }


        MultipartEntityBuilder entity = getEntity(sender.domain());

        // 收件人
        if(task.receivers().size() > 100){
            entity.addTextBody("to", createAddressList(task, sender), textPlainType);
        }
        else{
            StringBuilder receiverStr = new StringBuilder();
            for(MarketTaskReceiver taskReceiver : task.receivers()){
                if(!receiverStr.toString().equals(""))
                    receiverStr.append(";");
                receiverStr.append(taskReceiver.mailAddress());
            }
            entity.addTextBody("to", receiverStr.toString(), textPlainType);
        }


        // 邮件主体
        String subject = task.subject();
        subject = replaceSubjectMacro(subject);
        entity.addTextBody("subject", subject, textPlainType);
        entity.addTextBody("from", sender.senderAddress() + "@" + sender.domain().domainName(), textPlainType);
        entity.addTextBody("fromName", sender.senderName(), textPlainType);

        // 宏
        JSONObject xsmtpapi = new JSONObject();
        xsmtpapi.put("sub", getSub(task, sender.domain().creatorId()));
        entity.addTextBody("xsmtpapi", xsmtpapi.toString(), textPlainType);


        String htmlContent = task.content().content();
        htmlContent = replaceContentMacro(htmlContent);
        StringBuilder embeddedCid = new StringBuilder();
        //添加附件
        for(MarketTaskResource resource : task.resources()){
            if(!resource.urlName().contains("/admin-api/infra/file/"))
                continue;
            String strConfigId = StrUtil.subBefore(StrUtil.subAfter(resource.urlName(), "/admin-api/infra/file/", false), "/get/", false);
            String path = StrUtil.subAfter(resource.urlName(), "/get/", false);
            byte[] content = fileService.getFileContent(Long.parseLong(strConfigId), path);
            if(resource.resourceType().equals(MailboxMailResourceTypeEnum.ATTACHMENT.getValue())){
                entity.addBinaryBody("attachments", content, octetSteamType, resource.fileName());
            }else{
                String cidName = resource.urlName().substring(resource.urlName().lastIndexOf("/") + 1);
                if(embeddedCid.length() > 0)
                    embeddedCid.append(";");
                embeddedCid.append(cidName);
                htmlContent = htmlContent.replace(resource.urlName(), "cid:" + cidName);
                entity.addBinaryBody("embeddedImage", content, octetSteamType, resource.fileName());
            }

        }
        if(!embeddedCid.isEmpty()){
            entity.addTextBody("embeddedCid", embeddedCid.toString(), textPlainType);
        }

        // 正文
        entity.addTextBody("html", htmlContent, textPlainType);

        // replyTo
        if(sender.reply() != null){
            entity.addTextBody("replyTo", sender.reply().replyAddress(), textPlainType);
        }

        HttpResponse response = httpPost(mailSendUrl, entity);

        String errorMessage = "";
        if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            // 将 JSON 字符串解析为 JSONObject
            JSONObject jsonResponse = new JSONObject(EntityUtils.toString(response.getEntity()));

            if(jsonResponse.getInt("statusCode") == HttpStatus.SC_OK){
                // 提取 emailIdList 数组
                JSONArray emailIdListArray = jsonResponse.getJSONObject("info").getJSONArray("emailIdList");
                for (int i = 0; i < emailIdListArray.length(); i++) {
                    String receiverAddress = getReceiverAddress(emailIdListArray.getString(i));
                    String MessageId = getMessage(emailIdListArray.getString(i), sender.domain().domainName());
                    marketTaskReceiverRepository.updateMarketMailId(task.id(), receiverAddress, emailIdListArray.getString(i), MessageId);
                }
                // 更新状态
                marketTaskRepository.updateStatus(task.id(), MarketTaskStatusEnum.DONE.getValue());
            }else{
                errorMessage = "发送邮件出现错误，" + jsonResponse.getString("message");
            }

        } else {
            errorMessage = "发送邮件出现未知错误，请联系研发，错误码：" + response.getStatusLine().getStatusCode();
        }

        return errorMessage;
    }

    private String getMessage(String marketMailId, String domainName){
        if(marketMailId.lastIndexOf("$") >= 0){
            return marketMailId.substring(0, marketMailId.lastIndexOf("$"))+ "@" + domainName;
        }else
            return marketMailId;
    }

    private String getReceiverAddress(String marketMailId){
        if(marketMailId.lastIndexOf("$") >= 0){
            return marketMailId.substring(marketMailId.lastIndexOf("$") + 1);
        }else
            return marketMailId;
    }

    private JSONObject getSub(MarketTask task, Long ownerId) throws JSONException {
        SystemUser owner = systemUserRepository.findNullable(ownerId);
        if(owner == null)
            return null;

        // sub 收件人名称 收件人昵称 收件公司名称 收件公司简称
        JSONArray receiverName = new JSONArray();
        JSONArray receiverNickName = new JSONArray();
        JSONArray customerName = new JSONArray();
        JSONArray customerShortName = new JSONArray();

        // pubsub 手机 昵称 姓名 职位 日期 时间
        JSONArray userMobile = new JSONArray();
        JSONArray userNickName = new JSONArray();
        JSONArray userName = new JSONArray();
        JSONArray usePosition = new JSONArray();
        JSONArray date = new JSONArray();
        JSONArray time = new JSONArray();

        String nowDate = LocalDate.now().toString();
        String nowTime = LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"));

        for(MarketTaskReceiver receiver : task.receivers()){
            CustomerContact contact = customerContactRepository.findDetailById(receiver.contactId());
            receiverName.put(contact.name());
            receiverNickName.put(contact.nickName());
            customerName.put(contact.customer().name());
            customerShortName.put(contact.customer().shortName());
            userMobile.put(owner.mobile());
            userNickName.put(owner.nickname());
            userName.put(owner.username());
            usePosition.put(owner.position());
            date.put(nowDate);
            time.put(nowTime);
        }


        JSONObject sub = new JSONObject();
        sub.put("%receiverName%", receiverName);
        sub.put("%receiverNickName%", receiverNickName);
        sub.put("%customerName%", customerName);
        sub.put("%customerShortName%", customerShortName);

        sub.put("%userMobile%", userMobile);
        sub.put("%userNickName%", userNickName);
        sub.put("%userName%", userName);
        sub.put("%usePosition%", usePosition);
        sub.put("%date%", date);
        sub.put("%time%", time);
        return sub;
    }


    private String replaceSubjectMacro(String subject){
        subject = subject.replace("%收件人名称%", "%receiverName%");
        subject = subject.replace("%收件人昵称%", "%receiverNickName%");
        subject = subject.replace("%收件公司名称%", "%customerName%");
        subject = subject.replace("%收件公司简称%", "%customerShortName%");
        return subject;
    }

    private String replaceContentMacro(String content){
        content = content.replace("%收件人名称%", "%receiverName%");
        content = content.replace("%收件人昵称%", "%receiverNickName%");
        content = content.replace("%收件公司名称%", "%customerName%");
        content = content.replace("%收件公司简称%", "%customerShortName%");

        content = content.replace("%手机%", "%userMobile%");
        content = content.replace("%昵称%", "%userNickName%");
        content = content.replace("%姓名%", "%userName%");
        content = content.replace("%职位%", "%usePosition%");
        content = content.replace("%日期%", "%date%");
        content = content.replace("%时间%", "%time%");
        return content;
    }

    private HttpResponse httpPost(String postUrl,  MultipartEntityBuilder entity) throws IOException {
        HttpPost httpPost = new HttpPost(postUrl);
        CloseableHttpClient httpClient = HttpClients.createDefault();

        httpPost.setEntity(entity.build());

        HttpResponse response = httpClient.execute(httpPost);
        httpPost.releaseConnection();
        return response;
    }

    private MultipartEntityBuilder getEntity(MarketSettingDomain domain){
        MultipartEntityBuilder entity = MultipartEntityBuilder.create();
        entity.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
        entity.setCharset(StandardCharsets.UTF_8);

        // key
        entity.addTextBody("apiUser", domain.apiUser(), textPlainType);
        entity.addTextBody("apiKey", domain.apiKey(), textPlainType);
        return entity;
    }

    public void createWebHook(MarketSettingDomain domain) throws Exception {
        MultipartEntityBuilder entity = getEntity(domain);

        // url
        String url = "";
        // todo 需要根据AccountService捞获取服务器ip和后端端口
        url = "http://115.190.25.160:48080/crm-server/admin-api/infra/webhook/send-cloud/receive";

        if(webhookIsExist(domain, url))
            return;

        entity.addTextBody("url", url, textPlainType);
        entity.addTextBody("categoryName", domain.apiUser(), textPlainType);

        HttpResponse response = httpPost(webhookAddUrl, entity);
        getResponseInfo(response);

    }

    private boolean webhookIsExist(MarketSettingDomain domain, String url) throws Exception {
        MultipartEntityBuilder entity = getEntity(domain);

        entity.addTextBody("url", url, textPlainType);

        HttpResponse response = httpPost(webhookListUrl, entity);

        JSONObject responseInfo = getResponseInfo(response);
        JSONArray dataListArray = responseInfo.getJSONArray("dataList");
        return dataListArray.length() != 0;
    }

    private JSONObject getResponseInfo(HttpResponse response) throws Exception {
        if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            // 将 JSON 字符串解析为 JSONObject
            JSONObject jsonResponse = new JSONObject(EntityUtils.toString(response.getEntity()));
            if(jsonResponse.getInt("statusCode") == HttpStatus.SC_OK){
                // 提取 emailIdList 数组
                return jsonResponse.getJSONObject("info");
            }else{
                throw new Exception(jsonResponse.getString("message"));
            }

        } else {
            throw new Exception("错误码：" + response.getStatusLine().getStatusCode());
        }
    }

   public String createAddressList(MarketTask task,  MarketSettingSender sender) throws Exception {
       MultipartEntityBuilder entityAddress = getEntity(sender.domain());
       String name =  task.taskNo() + System.currentTimeMillis();
       String address = name + "@maillist.sendcloud.org";
       entityAddress.addTextBody("address", address, textPlainType);
       entityAddress.addTextBody("name",name, textPlainType);
       HttpResponse responseAddress = httpPost(addressListAddUrl, entityAddress);
       getResponseInfo(responseAddress);

       int postCount = (int) NumberUtil.div(task.receivers().size(), 10000, 0, RoundingMode.CEILING);
       System.out.println("this is post count " + postCount);
       for(int i = 0; i < postCount; i++){
           MultipartEntityBuilder entityMember = getEntity(sender.domain());
           entityMember.addTextBody("address", address, textPlainType);
           StringBuilder members = new StringBuilder();

           for(int receiverIndex = i * 10000; receiverIndex < task.receivers().size(); receiverIndex ++){
                if(members.length() > 0)
                    members.append(";");
               members.append(task.receivers().get(receiverIndex).mailAddress());


           }
           entityMember.addTextBody("members", members.toString(), textPlainType);
           HttpResponse responseMember = httpPost(addressMemberAddUrl, entityMember);
           getResponseInfo(responseMember);
       }


       return address;
   }

   public void handleRelyInfo(String messageId){
        if(messageId.isEmpty())
            return;

        MarketTaskReceiver receiver = marketTaskReceiverRepository.findByMessageId(messageId).orElse(null);
        if(receiver == null)
            return;

        MarketTask marketTask = marketTaskRepository.findNullable(receiver.taskId());
        if(marketTask == null)
            return;

       if(!receiver.isReply()){
           receiver = MarketTaskReceiverDraft.$.produce(receiver, draft -> draft.setIsReply(true)
           );
           marketTaskRepository.updateReplyCount(marketTask.id(), marketTask.replyCount() + 1);
           marketTaskReceiverRepository.update(receiver);
       }
   }
}
